import ConfigProvider from "./api/config-provider";
import ContentPropsProvider from "./api/content-props-provider";
import ContentProvider from "./api/content-provider";
import ContentUpdater from "./api/content-updater";
import {LocalAccessImpl} from "./local/local-access-impl";
import RemoteAccessGitee from "./remote/impl/remote-access-gitee";
import ContentNotExistException from "./api/exception/content-not-exist-exception";
import {DecisionMaker, Decisions} from "./api/decision-maker";
import FirstRunRecorder from "./api/first-run-recorder";

export enum SyncResult{
    DO_NOTHING = '什么也没做',
    NO_NEED_TO_SYNC = '本地书签和远程书签一致，无需同步',
    LOCAL_BOOKMARKS_UPDATED = '本地书签被更新',
    REMOTE_BOOKMARKS_UPDATED = '远程书签被更新'
}

export class BookmarkManager{

    private localBookmarkContentPropsProvider: ContentPropsProvider;
    private localBookmarkContentProvider: ContentProvider;
    private localBookmarkContentUpdater: ContentUpdater;

    private remoteBookmarkContentPropsProvider: ContentPropsProvider;
    private remoteBookmarkContentProvider: ContentProvider;
    private remoteBookmarkContentUpdater: ContentUpdater;

    constructor(public configProvider: ConfigProvider, public decisionMaker: DecisionMaker, public firstRunRecorder: FirstRunRecorder) {
        const localBookmarkPath = this.configProvider.get('local.bookmark-path');

        const localAccess = new LocalAccessImpl(localBookmarkPath);
        this.localBookmarkContentPropsProvider = localAccess;
        this.localBookmarkContentProvider = localAccess;
        this.localBookmarkContentUpdater = localAccess;

        const owner = this.configProvider.get('remote.gitee.owner');
        const repositoryName = this.configProvider.get('remote.gitee.repository-name');
        const bookmarkPath = this.configProvider.get('remote.gitee.bookmark-path');
        const accessToken = this.configProvider.get('remote.gitee.access-token');
        const remoteAccess= new RemoteAccessGitee(owner, repositoryName, bookmarkPath, accessToken);

        this.remoteBookmarkContentUpdater = remoteAccess;
        this.remoteBookmarkContentProvider = remoteAccess;
        this.remoteBookmarkContentPropsProvider = remoteAccess;
    }

    public async syncBookmark(): Promise<SyncResult> {
        let localBookmarkContent: string | undefined;
        let localBookmarkNotExist = false;
        let remoteBookmarkContent: string | undefined;
        let remoteBookmarkNotExist = false;
        try{
            localBookmarkContent = await this.localBookmarkContentProvider.getContent().then(buffer => buffer.toString('utf-8'));
        }catch (e) {
            if(e instanceof ContentNotExistException){
                localBookmarkNotExist = true;
            }else {
                throw e;
            }
        }

        try {
            remoteBookmarkContent = await this.remoteBookmarkContentProvider.getContent().then(buffer => buffer.toString('utf-8'));
        }catch (e) {
            if(e instanceof ContentNotExistException){
                remoteBookmarkNotExist = true;
            }else {
                throw e;
            }
        }

        if(localBookmarkContent == remoteBookmarkContent){
            console.log('本地书签和远程书签一致，无需同步')
            return Promise.resolve(SyncResult.NO_NEED_TO_SYNC);
        }

        // 1.本地书签不存在的情况
        // 如果远程书签存在，则拉取到本地
        // 如果远程书签不尊重，则不管它
        if(localBookmarkNotExist && remoteBookmarkNotExist){
            return Promise.resolve(SyncResult.DO_NOTHING);
        }
        if(localBookmarkNotExist && remoteBookmarkContent){
            await this.localBookmarkContentUpdater.update(Buffer.from(remoteBookmarkContent));
            return Promise.resolve(SyncResult.LOCAL_BOOKMARKS_UPDATED);
        }

        // 2. 本地书签存在的情况
        // 如果远程书签不存在，则推送到服务器
        // 如果远程书签也存在，就需要考虑一个问题：当前是不是首次运行
        //
        // 如果首次运行本程序的时候，本地和远程服务器上就已经存在书签，
        // 这种情况下，需要让用户来决定，是什么也不做，还是是要保留本地的书签，还是用远程的书签覆盖掉本地的书签
        // 如果要保留本地书签，那么就需要用本地书签覆盖远程服务器上的书签
        // 否则就用远程服务器上的书签覆盖本地书签
        //
        // 如果不是首次运行，那么（根据文件修改时间）比较本地书签和远程书签的版本，
        // 如果本地文件的版本更加新，那么就推送到远程服务器
        // 否则用远程服务器的版本覆盖本地的版本
        if(localBookmarkContent && remoteBookmarkNotExist ){
            await this.remoteBookmarkContentUpdater.update(Buffer.from(localBookmarkContent));
            return Promise.resolve(SyncResult.REMOTE_BOOKMARKS_UPDATED);
        }
        if(localBookmarkContent && remoteBookmarkContent){
            if(this.firstRunRecorder.isFirstRun()){
                const decision = await this.decisionMaker.makeDecision();
                if(decision == Decisions.DO_NOTHING){
                    return Promise.resolve(SyncResult.DO_NOTHING);
                }
                if(decision == Decisions.KEEP_LOCAL_VERSION){
                    await this.remoteBookmarkContentUpdater.update(Buffer.from(localBookmarkContent));
                    this.firstRunRecorder.setFirstRun(false);
                    return Promise.resolve(SyncResult.REMOTE_BOOKMARKS_UPDATED);
                }
                if(decision == Decisions.KEEP_REMOTE_VERSION){
                    await this.localBookmarkContentUpdater.update(Buffer.from(remoteBookmarkContent));
                    this.firstRunRecorder.setFirstRun(false);
                    return Promise.resolve(SyncResult.LOCAL_BOOKMARKS_UPDATED);
                }
            }else {
                // 不是首次运行，如果能够指定文件的修改时间的话，根据文件的修改时间来判断文件的版本
                // 否则报错
                const localBookmarkLastModifiedTime = await this.localBookmarkContentPropsProvider.getLastModifiedTime();
                const remoteBookmarkLastModifiedTime = await this.remoteBookmarkContentPropsProvider.getLastModifiedTime();
                if(localBookmarkLastModifiedTime > remoteBookmarkLastModifiedTime){
                    // 本地书签的版本比远程服务器上的要新
                    // 所以需要更新远程服务器上的版本
                    await this.remoteBookmarkContentUpdater.update(Buffer.from(localBookmarkContent));
                    return Promise.resolve(SyncResult.REMOTE_BOOKMARKS_UPDATED);
                }else {
                    // 更新本地书签
                    await this.localBookmarkContentUpdater.update(Buffer.from(remoteBookmarkContent));
                    return Promise.resolve(SyncResult.LOCAL_BOOKMARKS_UPDATED);
                }
            }
        }
        return Promise.resolve(SyncResult.DO_NOTHING);
    }
}
